home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 July: Mac OS SDK / Dev.CD Jul 96 SDK / Dev.CD Jul 96 SDK2.toast / Development Kits (Disc 2) / QuickDraw GX / Programming Stuff / GXEdit Library & Doc / GXEditDoc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-10  |  59.2 KB  |  2,741 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:            GXEditDoc.c
  3.     
  4.     Contains:
  5.     
  6.     Written by:    Barton R. House
  7.     
  8.     Copyright:    © 1993 by Apple Computer, Inc., All rights reserved.
  9.     
  10. */
  11.  
  12. /* GX includes */
  13.  
  14. #include "PrintingManager.h"
  15. #include "graphics routines.h"
  16. #include "graphics libraries.h"
  17. #include "font routines.h"
  18. #include "math routines.h"
  19. #include "layout routines.h"
  20. #include "layout types.h"
  21.  
  22. #include "GXEdit.h"
  23. #include "GXEditDebug.h"
  24. #include "GXEditDoc.h"
  25. #include "GXEditParagraph.h"
  26. #include "GXEditStyle.h"
  27. #include "GXEditSelection.h"
  28. #include "GXEditError.h"
  29. #include "GXEditUtils.h"
  30. #include "GXEditScrap.h"
  31. #include "GXEditReplace.h"
  32. #include "GXEditValidation.h"
  33. #include "GXEditLine.h"
  34.  
  35. #define kScrollRate        45
  36.  
  37. unsigned char *        gDefaultFonts[] = {
  38.                         "\pGeneva",
  39.                         "\pTimes",
  40.                         "\pMonaco"
  41.                 };
  42.  
  43. static void        CalcOffsets(DocPtr dp, short paragraphIndex);
  44. static void        CalcStarts(DocPtr dp, short paragraphIndex);
  45.  
  46. static void        InsertNewParagraph(DocPtr dp, short paragraphIndex, short paragraphOffset);
  47.  
  48. static void        CalcPrintPages(DocPtr dp, gxJob printJob, short * numPages, long *** pageStartsPtr);
  49. static gxShape         GetAPage(DocPtr dp, long docOffset);
  50.  
  51. static void         InitRunControl(gxRunControls * runControl);
  52.  
  53. static void        BlinkCursor(DocPtr dp);
  54.  
  55. static void         Insert(DocPtr dp, void * text, short startNumText, short styleIndex);
  56. static void         Clear(DocPtr dp);
  57. static void         Paste(DocPtr dp);
  58. static void         Copy(DocPtr dp);
  59.  
  60. static void        CalcPositionAndDraw(DocPtr dp, short startIndex);
  61. static void        Draw(DocPtr dp, long start, long end);
  62. static void        Position(DocPtr dp, long docOffset, long * start, long * end);
  63.  
  64. static void        HitTest(DocPtr dp, Point where, long * docOffset, Boolean * endOfLine, Boolean extend);
  65.  
  66. static void        CheckCaretVisibility(DocPtr dp);
  67.  
  68. static void        DoEraseToEndOfView(DocPtr dp);
  69.  
  70. static void        GetOffset(DocPtr dp, short offsetType, long * newOffset, Boolean * endOfLine);
  71.  
  72.  
  73. void NewDoc(DocHan * docHanPtr, Rect * viewRect, gxViewPort docViewPort, short leftMargin, short rightMargin)
  74. {
  75.     DocPtr            dp, * doc;
  76.     gxFont            defaultFont;
  77.     short            index;
  78.     short            numDefaultFonts;
  79.     gxViewPort        newViewPort;
  80.     gxShape            clip;
  81.     gxRectangle        rect;
  82.     StyleRec        defaultStyle;
  83.     
  84.     doc = (DocHan) NewHandle(sizeof(DocRec));
  85.     
  86.     *docHanPtr = doc;
  87.     
  88.     HLock((Handle) doc);
  89.     
  90.     dp = *doc;
  91.     
  92.     dp->magic = kGXEditMagic;
  93.     
  94.     /* initialize error reporting */
  95.     
  96.     dp->error = gx_edit_no_error;
  97.     dp->stickyError = gx_edit_no_error;
  98.     dp->errorProc = nil;
  99.  
  100.     dp->length = 0;
  101.     dp->lineWidth = viewRect->right - viewRect->left - leftMargin - rightMargin;
  102.     dp->leftMargin = leftMargin;
  103.     dp->rightMargin = rightMargin;
  104.     dp->viewHeight = viewRect->bottom - viewRect->top;
  105.     
  106.     dp->numText = 0;
  107.     
  108.     /* initialize the default gxStyle */
  109.     
  110.     dp->numStyles = 0;
  111.     dp->styles = (StyleHan) NewHandle(0);
  112.     
  113.     defaultStyle.textStyle = GXNewStyle();
  114.     
  115.     GXSetStyleTextSize(defaultStyle.textStyle, ff(24));
  116.     
  117.     /* initialize the default layout options */
  118.     
  119.     dp->currentLayoutOptions.width = ff(dp->lineWidth);
  120.     dp->currentLayoutOptions.flush = gxFlushLeft;
  121.     dp->currentLayoutOptions.just = gxNoJustification;
  122.     dp->currentLayoutOptions.flags = 0;                    /* no flags set */
  123.     dp->currentLayoutOptions.baselineRec = nil;
  124.     
  125.     /* initialize the default script and language */
  126.     
  127.     dp->currentPlatform = GXGetStyleEncoding(defaultStyle.textStyle,  &dp->currentScript, &dp->currentLanguage);
  128.         
  129.     /* find a good default gxFont */
  130.         
  131.     defaultFont = (gxFont) -1;
  132.  
  133.     numDefaultFonts = sizeof(gDefaultFonts) / sizeof(char *);
  134.     
  135.     for(index = 0; index < numDefaultFonts, defaultFont == (gxFont) -1; index++)
  136.         GXFindFonts(nil, gxFamilyFontName, 
  137.                             gxMacintoshPlatform, gxRomanScript, gxNoLanguage,
  138.                             gDefaultFonts[index][0], &gDefaultFonts[index][1],
  139.                             1, 1, &defaultFont);
  140.                             
  141.     if(defaultFont == (gxFont) -1)
  142.         GXFindFonts(nil, gxFamilyFontName,
  143.                             gxMacintoshPlatform, gxRomanScript, gxNoLanguage,
  144.                             0, nil, 1, 1, &defaultFont);
  145.                             
  146.     if(defaultFont != (gxFont) -1)
  147.         GXSetStyleFont(defaultStyle.textStyle, defaultFont);
  148.         
  149.     dp->numCurrentFonts = 1;
  150.     dp->currentFonts = (gxFont **) NewHandle(sizeof(gxFont));
  151.     (*dp->currentFonts)[0] = GXGetStyleFont(defaultStyle.textStyle);
  152.     
  153.     dp->numCurrentStyles = 1;
  154.     dp->currentStyles = (short **) NewHandle(sizeof(short));
  155.     (*dp->currentStyles)[0] = AddDocTextStyle(dp, defaultStyle.textStyle);
  156.     
  157.     GXDisposeStyle(defaultStyle.textStyle);
  158.  
  159.     /* set the view rect and gxViewPort */
  160.     
  161.     dp->viewRect = *viewRect;
  162.     dp->top = 0;
  163.     dp->maxTop = 0;
  164.     
  165.     newViewPort = GXCopyToViewPort(nil, docViewPort);
  166.     GXSetViewPortParent(newViewPort, docViewPort);
  167.     
  168.     rect.top = ff(viewRect->top);
  169.     rect.left = ff(viewRect->left);
  170.     rect.right = ff(viewRect->right);
  171.     rect.bottom = ff(viewRect->bottom);
  172.     clip = GXNewRectangle(&rect);
  173.     
  174.     /* This ignores is needed because we do not keep track of the current
  175.           clip of the view port.  Thus, we will often set the clip to the same rect
  176.           which generates a notice*/
  177.  
  178. #ifdef debugging
  179.     GXIgnoreGraphicsNotice(clip_already_set);
  180. #endif
  181.  
  182.     GXSetViewPortClip(newViewPort, clip);
  183.     
  184. #ifdef debugging
  185.     GXPopGraphicsNotice();
  186. #endif
  187.     
  188.     GXDisposeShape(clip);
  189.     
  190.     dp->docViewPort = newViewPort;
  191.  
  192.     /* setup layout orientation */
  193.     
  194.     dp->verticalText = false;            /* initial value is non-vertical */
  195.         
  196.     /* the document has not been drawn */
  197.     
  198.     dp->drawn = false;
  199.     
  200.     if(dp->verticalText)
  201.         dp->bottomClear = dp->viewRect.left;
  202.     else
  203.         dp->bottomClear = dp->viewRect.bottom;
  204.     
  205.     /* allocate offscreen gxBitmap and viewport */
  206.     
  207.     dp->offscreenBytes = nil;
  208.     dp->offscreenPort = nil;
  209.     dp->offscreenDevice = nil;
  210.     dp->offscreenGroup = nil;
  211.     dp->offscreenBitmap = nil;
  212.     
  213.     gxEditBuildOffscreen(dp);
  214.     
  215.     /* now initialize an empty paragraph */
  216.     
  217.     dp->numParagraphs = 1;
  218.     dp->paragraphs = (ParaHan) NewHandle(sizeof(ParaRec));
  219.     
  220.     HLock((Handle) dp->paragraphs);
  221.     
  222.     gxEditNewParagraph(dp, *dp->paragraphs, (*dp->currentStyles)[0]);
  223.     
  224.     HUnlock((Handle) dp->paragraphs);
  225.  
  226.     CalcOffsets(dp, 0);
  227.     CalcStarts(dp, 0);
  228.         
  229.     /* selection at the start of the document */
  230.     
  231.     dp->emptyStyle = (*dp->currentStyles)[0];
  232.     SetSelection(dp, 0, 0, false, false, true);
  233.                 
  234.     /* mark the document as unactive */
  235.     
  236.     dp->active = false;
  237.     
  238.     /* setup the scrap to be empty */
  239.     
  240.     dp->scrap.numRuns = 0;
  241.     dp->scrap.runs = (NewRunHan) NewHandle(0);
  242.     
  243.     
  244.     HUnlock((Handle) doc);
  245.         
  246. }
  247.  
  248. void DisposeDoc(DocHan doc)
  249. {
  250.     DocPtr            dp;
  251.     ParaPtr            pp;
  252.     short            paragraphIndex;
  253.     StylePtr            sp;
  254.     short            styleIndex;
  255.     
  256.     HLock((Handle) doc);
  257.     
  258.     dp = *doc;
  259.     
  260.     gxEditDisposeScrap(dp);
  261.     
  262.     HLock((Handle) dp->paragraphs);
  263.     
  264.     pp = *dp->paragraphs;
  265.     
  266.     for(paragraphIndex=0; paragraphIndex < dp->numParagraphs; paragraphIndex++, pp++)
  267.         gxEditDisposeParagraph(dp, pp);
  268.         
  269.     HUnlock((Handle) dp->paragraphs);
  270.     
  271.     DisposeHandle((Handle) dp->paragraphs);
  272.  
  273.     HLock((Handle) dp->styles);
  274.     
  275.     sp = *dp->styles;
  276.     
  277.     for(styleIndex=0; styleIndex < dp->numStyles; styleIndex++, sp++)
  278.         GXDisposeStyle(sp->textStyle);
  279.         
  280.     HUnlock((Handle) dp->styles);
  281.     
  282.     DisposeHandle((Handle) dp->styles);
  283.     
  284.     DisposeHandle((Handle) dp->currentStyles);
  285.     
  286.     GXDisposeViewPort(dp->docViewPort);
  287.     
  288.     gxEditDisposeOffscreen(dp);
  289.             
  290.     HUnlock((Handle) doc);
  291.     
  292.     DisposeHandle((Handle) doc);
  293. }
  294.  
  295. void DocSetSelection(DocPtr dp, long selStart, long selEnd)
  296. {
  297.     SetSelection(dp, selStart, selEnd, true, false, true);
  298.     
  299.     Draw(dp, 0, dp->viewHeight);
  300. }
  301.  
  302. void DocInsert(DocPtr dp, void *text, short startNumText)
  303. {
  304.     short        styleIndex;
  305.     
  306.     /* make sure we are adding using the current script and lanuaguge */
  307.     
  308.     styleIndex = SetDocStyleEncoding(dp, (*dp->currentStyles)[0], dp->currentPlatform, dp->currentScript, dp->currentLanguage);
  309.     
  310.     Insert(dp, text, startNumText, styleIndex);
  311.     CheckCaretVisibility(dp);
  312.     Draw(dp, 0, dp->viewHeight);
  313. }
  314.  
  315. void DocClear(DocPtr dp)
  316. {
  317.     if(dp->selection.startDocOffset == dp->selection.endDocOffset)
  318.         return;        /* nothing to clear */
  319.         
  320.     Clear(dp);
  321.     
  322.     /* reflow the document */
  323.     
  324.     while(DocReflow(dp)) ;
  325.     
  326.     CheckCaretVisibility(dp);
  327.  
  328.     Draw(dp, 0, dp->viewHeight);
  329.         
  330.     
  331. }
  332.  
  333. long DocHitTest(DocPtr dp, Point where)
  334. {
  335.     long                docOffset;
  336.     Boolean                endOfLine;
  337.     
  338.     HitTest(dp, where, &docOffset, &endOfLine, false);
  339.     
  340.     return(docOffset);
  341.     
  342. }
  343.  
  344. void DocUpdate(DocPtr dp, gxRectangle * updateRect)
  345. {
  346.     ParaPtr            pp;
  347.     short            paragraphIndex;
  348.     long                start, end;
  349.  
  350.     if(dp->verticalText) {
  351.     
  352.         start = FixedToInt(updateRect->right);
  353.         end = FixedToInt(updateRect->left);
  354.         
  355.         if(start < end)
  356.             gxEditPostError(dp, gx_edit_internal_fatal_error);
  357.             
  358.         if(start > dp->viewRect.right)
  359.             start =  dp->viewRect.right;
  360.         
  361.         if(end < dp->viewRect.left)
  362.             end = dp->viewRect.left;
  363.         
  364.         if(start < end)
  365.             return;
  366.  
  367.     } else {
  368.  
  369.         start = FixedToInt(updateRect->top);
  370.         end = FixedToInt(updateRect->bottom);
  371.  
  372.         if(start > end)
  373.             gxEditPostError(dp, gx_edit_internal_fatal_error);
  374.             
  375.         if(start < dp->viewRect.top)
  376.             start = dp->viewRect.top;
  377.     
  378.         if(end > dp->viewRect.bottom)
  379.             end = dp->viewRect.bottom;
  380.         
  381.         if(start > end)
  382.             return;
  383.     }
  384.     
  385.     if(dp->dirty)
  386.         CalcStarts(dp, 0);
  387.         
  388.     HLock((Handle) dp->paragraphs);
  389.     
  390.     /* map the view area coords to doc coords */
  391.     
  392.     if(dp->verticalText) {
  393.         start = dp->viewRect.right - start + dp->top;
  394.         end = dp->viewRect.right - end + dp->top;
  395.     } else {
  396.         start = start - dp->viewRect.top + dp->top;
  397.         end = end - dp->viewRect.top + dp->top;
  398.     }
  399.     
  400.     /* loop through all of the paragraphs, draw paragraphs that fall in the range */
  401.     
  402.     /* this loop should be optimized in the future */
  403.     
  404.     pp = *dp->paragraphs;
  405.     
  406.     for(paragraphIndex=0; paragraphIndex < dp->numParagraphs; pp++, paragraphIndex++)
  407.         if((pp->start + GetParagraphHeight(dp, pp)) >= start && (pp->start < end)) {
  408.             
  409.             pp->drawn = false;
  410.             DrawParagraph(dp, pp, start, end);
  411.             
  412.         }
  413.             
  414.     /* erase from the last paragraph to end of view if necessary */
  415.     
  416.     if(paragraphIndex == dp->numParagraphs)
  417.         DoEraseToEndOfView(dp);
  418.     
  419.     dp->drawn = true;
  420.         
  421.     HUnlock((Handle) dp->paragraphs);
  422.         
  423. }
  424.  
  425. void DocClick(DocPtr dp, Point where, Boolean extend)
  426. {
  427.     long        docOffset;
  428.     long        startDocOffset;
  429.     long        endDocOffset;
  430.     Boolean    endOfLine;
  431.     Boolean    done;
  432.     long        oldDocOffset;
  433.     Boolean    firstTime;
  434.     
  435.     HitTest(dp, where, &docOffset, &endOfLine, extend);
  436.  
  437.     if(extend) {
  438.     
  439.         startDocOffset = dp->selection.startDocOffset;
  440.         endDocOffset = dp->selection.endDocOffset;
  441.         
  442.     } else
  443.         startDocOffset = docOffset;
  444.     
  445.     done = false;
  446.     firstTime = true;
  447.     
  448.     while(!done) {
  449.         
  450.         if(extend) {
  451.         
  452.             if(docOffset > startDocOffset)
  453.                 SetSelection(dp, startDocOffset, docOffset, true, endOfLine, true);
  454.             else
  455.                 SetSelection(dp, docOffset, endDocOffset, true, endOfLine, true);
  456.                 
  457.         } else {
  458.         
  459.             if(docOffset > startDocOffset)
  460.                 SetSelection(dp, startDocOffset, docOffset, true, endOfLine, true);
  461.             else if(!firstTime || docOffset != dp->selection.startDocOffset || docOffset != dp->selection.endDocOffset)
  462.                 SetSelection(dp, docOffset, startDocOffset, true, endOfLine, true);
  463.                 
  464.         }
  465.         
  466.         Draw(dp, 0, dp->viewHeight);
  467.         
  468.         oldDocOffset = docOffset;
  469.         
  470.         do {
  471.         
  472.             if((done = !StillDown()))
  473.                 break;
  474.             
  475.             GetMouse(&where);
  476.             
  477.             HitTest(dp, where, &docOffset, &endOfLine, (firstTime ? extend : true));
  478.             
  479.             if(dp->verticalText) {
  480.                 if(where.h > dp->viewRect.right)
  481.                     DocScroll(dp, kScrollRate);
  482.                 else if(where.h < dp->viewRect.left)
  483.                     DocScroll(dp, -kScrollRate);
  484.             } else {
  485.                 if(where.v < dp->viewRect.top)
  486.                     DocScroll(dp, kScrollRate);
  487.                 else if(where.v > dp->viewRect.bottom)
  488.                     DocScroll(dp, -kScrollRate);
  489.             }
  490.             
  491.         } while(docOffset == oldDocOffset);
  492.         
  493.         firstTime = false;
  494.         
  495.     }
  496.         
  497. }
  498.  
  499. void DocScroll(DocPtr dp, short dv)
  500. {
  501.     RgnHandle        updateRgn;
  502.     long            top;
  503.     long            bottom;
  504.     ParaPtr            pp;
  505.     LinePtr            lp;
  506.     short            paraIndex;
  507.     short            lineIndex;
  508.     
  509.     if(dv < 0)
  510.         dv = (dv < (dp->top - dp->maxTop) ? (dp->top - dp->maxTop) : dv);
  511.     else
  512.         dv = (dv > dp->top ? dp->top : dv);
  513.         
  514.     if(dv == 0)
  515.         return;
  516.     
  517.     updateRgn = NewRgn();
  518.     
  519.     if(dp->verticalText)
  520.         ScrollRect(&dp->viewRect, -dv, 0, updateRgn);
  521.     else
  522.         ScrollRect(&dp->viewRect, 0, dv, updateRgn);
  523.     
  524.     DisposeRgn(updateRgn);
  525.     
  526.     if(dv < 0) {
  527.         top = dp->viewHeight + dv;
  528.         bottom = dp->viewHeight;
  529.     } else {
  530.         top = 0;
  531.         bottom = dv;
  532.     }    
  533.     dp->top -= dv;
  534.  
  535.     /* mark any gxLine that falls in this range not drawn */
  536.     
  537.     top += dp->top;
  538.     bottom += dp->top;
  539.     
  540.     if(dp->dirty)            /* this shouldn't happen -- we need to test because we use paragraph starts */
  541.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  542.     
  543.     HLock((Handle) dp->paragraphs);
  544.     
  545.     pp = *dp->paragraphs;
  546.     for(paraIndex=0; paraIndex < dp->numParagraphs; paraIndex++, pp++)
  547.         if(pp->start < bottom && (pp->start + GetParagraphHeight(dp, pp)) > top)
  548.             for(lp = *pp->lines, lineIndex=0; lineIndex < pp->numLines; lineIndex++, lp++)
  549.                 if((pp->start + lp->start) < bottom && (pp->start + lp->start + lp->height) > top)
  550.                     lp->drawn = false;
  551.         
  552.     HUnlock((Handle) dp->paragraphs);
  553.     
  554.     Draw(dp, 0, dp->viewHeight);
  555.     
  556. }
  557.  
  558. long DocHeight(DocPtr dp)
  559. {
  560.     if(dp->dirty)
  561.         CalcStarts(dp, 0);
  562.     
  563.     return(dp->length);
  564. }
  565.  
  566. void DocSize(DocPtr dp, Rect * viewRect)
  567. {
  568.     gxShape            clip;
  569.     gxRectangle        rect;
  570.     short            paraIndex;
  571.     ParaPtr            pp;
  572.     LinePtr            lp;
  573.     short            lineIndex;
  574.     
  575.     dp->viewRect = *viewRect;
  576.     
  577.     rect.top = ff(viewRect->top);
  578.     rect.left = ff(viewRect->left);
  579.     rect.right = ff(viewRect->right);
  580.     rect.bottom = ff(viewRect->bottom);
  581.  
  582.     clip = GXNewRectangle(&rect);
  583.  
  584.     /* This ignores is needed because we do not keep track of the current
  585.           clip of the view port.  Thus, we will often set the clip to the same rect
  586.           which generates a notice*/
  587.  
  588. #ifdef debugging
  589.     GXIgnoreGraphicsNotice(clip_already_set);
  590. #endif
  591.  
  592.     GXSetViewPortClip(dp->docViewPort, clip);
  593.     
  594. #ifdef debugging
  595.     GXPopGraphicsNotice();
  596. #endif
  597.     
  598.     GXDisposeShape(clip);
  599.  
  600.     DocSetMaxTop(dp);
  601.     
  602.     /* update the offscreen gxBitmap */
  603.     
  604.     gxEditBuildOffscreen(dp);
  605.  
  606.     /* change the line width and view height */
  607.     
  608.     if(dp->verticalText) {
  609.         dp->lineWidth = dp->viewRect.bottom - dp->viewRect.top - dp->leftMargin - dp->rightMargin;
  610.         dp->viewHeight = dp->viewRect.right - dp->viewRect.left;
  611.     } else {
  612.         dp->lineWidth = dp->viewRect.right - dp->viewRect.left - dp->leftMargin - dp->rightMargin;
  613.         dp->viewHeight = dp->viewRect.bottom - dp->viewRect.top;
  614.     }
  615.     
  616.     /* change the line width for all of the paragraphs */
  617.     
  618.     pp = *dp->paragraphs;
  619.     
  620.     for(paraIndex = 0; paraIndex < dp->numParagraphs; paraIndex++, pp++) {
  621.     
  622.         if(pp->width != dp->lineWidth) {
  623.             
  624.             pp->width = dp->lineWidth;
  625.             pp->layoutOptions.width = ff(pp->width);
  626.             
  627.             if(pp->numLines) {
  628.             
  629.                 pp->reflow = true;
  630.                 (*pp->lines)[0].reflow = true;
  631.                 
  632.                 /* make sure we mark all lines as dirty so that a new layout calculation is forced */
  633.                 
  634.                 lp = *pp->lines;
  635.                 
  636.                 for(lineIndex = 0; lineIndex < pp->numLines; lineIndex++, lp++)
  637.                     lp->dirty = true;
  638.                 
  639.             }
  640.             
  641.         }
  642.         
  643.     }
  644.     
  645.     /* mark the entire document as not drawn */
  646.     
  647.     dp->drawn = false;
  648.         
  649. }    
  650.     
  651. long DocSetTop(DocPtr dp, long top)
  652. {
  653.     short    dv;
  654.     
  655.     if(top > dp->maxTop)
  656.         top = dp->maxTop;
  657.     
  658.     dv = dp->top - top;
  659.     
  660.     if(dv != 0)
  661.         DocScroll(dp, dv);
  662.     
  663.     return(dp->top);
  664. }
  665.  
  666. long DocGetTop(DocPtr dp)
  667. {
  668.     return(dp->top);
  669. }
  670.  
  671. long DocGetMaxTop(DocPtr dp)
  672. {
  673.     return(dp->maxTop);
  674. }
  675.  
  676. void DocKey(DocPtr dp, char key)
  677. {
  678.     long        startOffset;
  679.     Boolean    setAndDraw = false;
  680.     Boolean    setMaxLineOffset;
  681.     Boolean    endOfLine;
  682.     
  683.     endOfLine = dp->selection.endOfLine;
  684.         
  685.     switch(key) {
  686.     case '\b':
  687.     
  688.         if(dp->selection.startDocOffset == dp->selection.endDocOffset &&  dp->selection.startDocOffset != 0) {
  689.             startOffset = dp->selection.endDocOffset;
  690.                GetOffset(dp, kPreviousOffset, &startOffset, &endOfLine);
  691.             SetSelection(dp, startOffset, dp->selection.endDocOffset, false, endOfLine, true);
  692.         }        
  693.         
  694.         DocClear(dp);
  695.         
  696.         break;
  697.         
  698.     case 0x1c:        /* left arrow */
  699.     
  700.     
  701.         if(dp->verticalText) {
  702.             startOffset = dp->selection.endDocOffset;
  703.             GetOffset(dp, kDownOffset, &startOffset, &endOfLine);
  704.         } else {
  705.             startOffset = dp->selection.startDocOffset;
  706.             GetOffset(dp, kVisualLeftOffset, &startOffset, &endOfLine);
  707.         }
  708.         
  709.         
  710.         setAndDraw = true;
  711.         setMaxLineOffset = !dp->verticalText;
  712.         
  713.         break;
  714.                     
  715.     case 0x1d:        /* right arrow */
  716.     
  717.         if(dp->verticalText) {
  718.             startOffset = dp->selection.startDocOffset;
  719.             GetOffset(dp, kUpOffset, &startOffset, &endOfLine);
  720.         } else {
  721.             startOffset = dp->selection.endDocOffset;
  722.             GetOffset(dp, kVisualRightOffset, &startOffset, &endOfLine);
  723.         }
  724.         
  725.         setAndDraw = true;
  726.         setMaxLineOffset = !dp->verticalText;
  727.             
  728.         break;
  729.             
  730.     case 0x1e:        /* up arrow */
  731.     
  732.         startOffset = dp->selection.startDocOffset;
  733.  
  734.         if(dp->verticalText)
  735.             GetOffset(dp, kVisualLeftOffset, &startOffset, &endOfLine);
  736.         else
  737.             GetOffset(dp, kUpOffset, &startOffset, &endOfLine);
  738.                 
  739.         setAndDraw = true;
  740.         setMaxLineOffset = dp->verticalText;
  741.         
  742.         break;    
  743.                     
  744.     case 0x1f:        /* down arrow */
  745.  
  746.         startOffset = dp->selection.endDocOffset;
  747.         
  748.         if(dp->verticalText)
  749.             GetOffset(dp, kVisualRightOffset, &startOffset, &endOfLine);
  750.         else
  751.             GetOffset(dp, kDownOffset, &startOffset, &endOfLine);
  752.         
  753.         setAndDraw = true;
  754.         setMaxLineOffset = dp->verticalText;            
  755.     
  756.         break;
  757.         
  758.     default:
  759.         DocInsert(dp, (void *) &key, 1);
  760.         break;
  761.     }
  762.     
  763.     if(setAndDraw) {
  764.     
  765.         SetSelection(dp, startOffset, startOffset, false, endOfLine, setMaxLineOffset);
  766.         Draw(dp, 0, dp->viewHeight);        
  767.     }
  768. }
  769.  
  770. void DocSetTextFonts(DocPtr dp, short numFonts, gxFont * srcFonts, gxFont * dstFonts)
  771. {
  772.     short        * newStyles;
  773.     
  774.     if(dp->numCurrentStyles != 0) {
  775.     
  776.         newStyles = (short *) NewPtr(dp->numCurrentStyles * sizeof(short));
  777.         
  778.         HLock((Handle) dp->currentStyles);
  779.         
  780.         ModifyStyleTextFonts(dp, numFonts, srcFonts, dstFonts, dp->numCurrentStyles, *dp->currentStyles, newStyles);
  781.         
  782.         if(SetSelectionStyles(dp, dp->numCurrentStyles, *dp->currentStyles, newStyles))
  783.             CalcPositionAndDraw(dp, dp->selection.startParaIndex);
  784.                 
  785.         HUnlock((Handle) dp->currentStyles);
  786.         
  787.         DisposePtr((Ptr) newStyles);
  788.             
  789.         SetSelection(dp, dp->selection.startDocOffset, dp->selection.endDocOffset, false, dp->selection.endOfLine, false);
  790.         
  791.     } else
  792.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  793.     
  794. }
  795.  
  796. void DocGetTextFonts(DocPtr dp, short * numFonts, gxFont * fonts)
  797. {
  798.  
  799.     if(numFonts != nil)
  800.         *numFonts = dp->numCurrentFonts;
  801.     
  802.     if(fonts != nil)
  803.         BlockMove((Ptr) *dp->currentFonts, (Ptr) fonts, sizeof(gxFont) * dp->numCurrentFonts);
  804. }
  805.  
  806. void DocSetTextSize(DocPtr dp, short size)
  807. {
  808.     short        * newStyles;
  809.     
  810.     if(dp->numCurrentStyles != 0) {
  811.     
  812.         newStyles = (short *) NewPtr(dp->numCurrentStyles * sizeof(short));
  813.         
  814.         HLock((Handle) dp->currentStyles);
  815.         
  816.         ModifyStyleTextSize(dp, size, dp->numCurrentStyles, *dp->currentStyles, newStyles);
  817.         
  818.         if(SetSelectionStyles(dp, dp->numCurrentStyles, *dp->currentStyles, newStyles))
  819.             CalcPositionAndDraw(dp, dp->selection.startParaIndex);
  820.                 
  821.         HUnlock((Handle) dp->currentStyles);
  822.         
  823.         DisposePtr((Ptr) newStyles);
  824.             
  825.         SetSelection(dp, dp->selection.startDocOffset, dp->selection.endDocOffset, false, dp->selection.endOfLine, false);
  826.         
  827.     } else
  828.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  829.     
  830. }
  831.  
  832. short DocGetTextSize(DocPtr dp)
  833. {
  834.     return(dp->currentSize);
  835. }
  836.  
  837. void DocSetFeatures(DocPtr dp, gxFont fontId, short numFeatureGroups,
  838.                                     short * srcFeatureGroupSizes,
  839.                                     gxRunFeature ** srcFeatureGroups,
  840.                                     short * dstFeatureGroupSizes,
  841.                                     gxRunFeature ** dstFeatureGroups)
  842. {
  843.     short            ** newStyles;
  844.     
  845.     if(dp->numCurrentStyles != 0) {
  846.     
  847.         newStyles = (short **) NewHandle(dp->numCurrentStyles * sizeof(short));
  848.         
  849.         HLock((Handle) dp->currentStyles);
  850.         HLock((Handle) newStyles);
  851.         
  852.         ModifyStyleFeatures(dp, fontId, numFeatureGroups,
  853.                                         srcFeatureGroupSizes, srcFeatureGroups,
  854.                                         dstFeatureGroupSizes, dstFeatureGroups,
  855.                                         dp->numCurrentStyles, *dp->currentStyles, *newStyles);
  856.         
  857.         if(SetSelectionStyles(dp, dp->numCurrentStyles, *dp->currentStyles, *newStyles))
  858.             CalcPositionAndDraw(dp, dp->selection.startParaIndex);
  859.                 
  860.         HUnlock((Handle) dp->currentStyles);
  861.         HUnlock((Handle) newStyles);
  862.         
  863.         DisposeHandle((Handle) newStyles);
  864.             
  865.         SetSelection(dp, dp->selection.startDocOffset, dp->selection.endDocOffset, false, dp->selection.endOfLine, false);
  866.         
  867.     } else
  868.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  869.     
  870. }
  871.  
  872. void DocGetFeatures(DocPtr dp, gxFont fontId, short * numFeatureGroupsPtr,
  873.                                     short *** featureGroupSizesPtr,
  874.                                     gxRunFeature **** featureGroupsPtr)
  875. {
  876.  
  877.     if(dp->numCurrentStyles != 0) {
  878.     
  879.         HLock((Handle) dp->currentStyles);
  880.         
  881.         UnionStyleFeatures(dp, dp->numCurrentStyles, *dp->currentStyles, 
  882.                                 fontId, numFeatureGroupsPtr, featureGroupSizesPtr, featureGroupsPtr);
  883.         
  884.         HUnlock((Handle) dp->currentStyles);
  885.     
  886.         
  887.     } else {
  888.         
  889.         *numFeatureGroupsPtr = 0;
  890.         *featureGroupSizesPtr = nil;
  891.         *featureGroupsPtr = nil;
  892.     }
  893.  
  894. }
  895.  
  896. void DocGetSelectionStyles(DocPtr dp, short * numStyles, gxStyle * styles)
  897. {
  898.     short        i;
  899.  
  900.     if(numStyles != nil)
  901.         *numStyles = dp->numCurrentStyles;
  902.         
  903.     if(styles != nil)
  904.         for(i=0; i<dp->numCurrentStyles;i++)
  905.             styles[i] = GetDocStyle(dp, (*dp->currentStyles)[i])->textStyle;
  906.     
  907. }
  908.  
  909. void DocSetSelectionStyles(DocPtr dp, gxStyle * newTextStyles)
  910. {
  911.     short            * newStyles;
  912.     short            i;
  913.     StyleRec            newStyle;
  914.     
  915.     if(dp->numCurrentStyles != 0) {
  916.     
  917.         newStyles = (short *) NewPtr(dp->numCurrentStyles * sizeof(short));
  918.         
  919.         for(i=0; i<dp->numCurrentStyles; i++) {
  920.         
  921.             InitDocStyle(newTextStyles[i], &newStyle);
  922.             
  923.             newStyles[i] = FindDocStyle(dp, &newStyle);
  924.             
  925.             if(newStyles[i] == -1)
  926.                 newStyles[i] = AddDocTextStyle(dp, newTextStyles[i]);
  927.                 
  928.         }
  929.         
  930.         HLock((Handle) dp->currentStyles);
  931.         
  932.         if(SetSelectionStyles(dp, dp->numCurrentStyles, *dp->currentStyles, newStyles))
  933.             CalcPositionAndDraw(dp, dp->selection.startParaIndex);
  934.  
  935.         HUnlock((Handle) dp->currentStyles);
  936.         
  937.         DisposePtr((Ptr) newStyles);
  938.             
  939.         SetSelection(dp, dp->selection.startDocOffset, dp->selection.endDocOffset, false, dp->selection.endOfLine, false);
  940.         
  941.     } else
  942.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  943.  
  944. }
  945.  
  946. void DocSetVariations(DocPtr dp, gxFont fontId, short numVariations, gxFontVariation * variations)
  947. {
  948.     short            ** newStyles;
  949.     
  950.     if(dp->numCurrentStyles != 0) {
  951.     
  952.         newStyles = (short **) NewHandle(dp->numCurrentStyles * sizeof(short));
  953.         
  954.         HLock((Handle) dp->currentStyles);
  955.         HLock((Handle) newStyles);
  956.         
  957.         ModifyStyleVariations(dp, fontId, numVariations, variations, dp->numCurrentStyles, *dp->currentStyles, *newStyles);
  958.         
  959.         if(SetSelectionStyles(dp, dp->numCurrentStyles, *dp->currentStyles, *newStyles))
  960.             CalcPositionAndDraw(dp, dp->selection.startParaIndex);
  961.  
  962.         HUnlock((Handle) dp->currentStyles);
  963.         HUnlock((Handle) newStyles);
  964.         
  965.         DisposeHandle((Handle) newStyles);
  966.             
  967.         SetSelection(dp, dp->selection.startDocOffset, dp->selection.endDocOffset, false, dp->selection.endOfLine, false);
  968.         
  969.     } else
  970.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  971.  
  972. }
  973.  
  974. void DocGetVariations(DocPtr dp, gxFont fontId, short * numInstancesPtr,
  975.                         short *** instanceSizesPtr, gxFontVariation **** instancesPtr)
  976. {
  977.     if(dp->numCurrentStyles != 0) {
  978.     
  979.         HLock((Handle) dp->currentStyles);
  980.         
  981.         UnionStyleVariations(dp, dp->numCurrentStyles, *dp->currentStyles,
  982.                                 fontId, numInstancesPtr, instanceSizesPtr, instancesPtr);
  983.         
  984.         HUnlock((Handle) dp->currentStyles);
  985.     
  986.         
  987.     } else {
  988.         
  989.         *numInstancesPtr = 0;
  990.         *instanceSizesPtr = nil;
  991.         *instancesPtr = nil;
  992.     
  993.     }
  994.     
  995. }
  996.  
  997. void DocGetRunControls(DocPtr dp, gxRunControls * runControls, gxRunControls * mask)
  998. {
  999.     if(dp->numCurrentStyles != 0) {
  1000.     
  1001.         HLock((Handle) dp->currentStyles);
  1002.         
  1003.         UnionStyleRunControls(dp, dp->numCurrentStyles, *dp->currentStyles, runControls, mask);
  1004.     
  1005.         HUnlock((Handle) dp->currentStyles);
  1006.                 
  1007.     } else
  1008.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  1009.  
  1010. }
  1011.  
  1012. void DocSetRunControls(DocPtr dp, gxRunControls * runControls, gxRunControls * mask)
  1013. {
  1014.     short            ** newStyles;
  1015.  
  1016.     if(dp->numCurrentStyles != 0) {
  1017.     
  1018.         newStyles = (short **) NewHandle(dp->numCurrentStyles * sizeof(short));
  1019.         
  1020.         HLock((Handle) dp->currentStyles);
  1021.         HLock((Handle) newStyles);
  1022.         
  1023.         ModifyStyleRunControls(dp, runControls, mask, dp->numCurrentStyles, *dp->currentStyles, *newStyles);
  1024.         
  1025.         if(SetSelectionStyles(dp, dp->numCurrentStyles, *dp->currentStyles, *newStyles))
  1026.             CalcPositionAndDraw(dp, dp->selection.startParaIndex);
  1027.  
  1028.         HUnlock((Handle) dp->currentStyles);
  1029.         HUnlock((Handle) newStyles);
  1030.         
  1031.         DisposeHandle((Handle) newStyles);
  1032.             
  1033.         SetSelection(dp, dp->selection.startDocOffset, dp->selection.endDocOffset, false, dp->selection.endOfLine, false);
  1034.         
  1035.     } else
  1036.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  1037.     
  1038. }
  1039.  
  1040.  
  1041. void DocGetFontRunControls(DocPtr dp, gxFont fontID, gxRunControls * runControls, gxRunControls * mask)
  1042. {
  1043.     if(dp->numCurrentStyles != 0) {
  1044.     
  1045.         HLock((Handle) dp->currentStyles);
  1046.         
  1047.         UnionFontRunControls(dp, dp->numCurrentStyles, *dp->currentStyles, fontID, runControls, mask);
  1048.     
  1049.         HUnlock((Handle) dp->currentStyles);
  1050.                 
  1051.     } else
  1052.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  1053.  
  1054. }
  1055. void DocGetLayoutOptions(DocPtr dp, gxLayoutOptions * options, gxLayoutOptions * optionsMask)
  1056. {
  1057.     ParaPtr            pp;
  1058.     short            startParagraphIndex;
  1059.     short            endParagraphIndex;
  1060.     short            paragraphIndex;
  1061.     short            start;
  1062.     short            end;
  1063.     Boolean            firstTime;
  1064.             
  1065.     /* find the current selected paragraph */
  1066.     
  1067.     startParagraphIndex = dp->selection.startParaIndex;
  1068.     endParagraphIndex = dp->selection.endParaIndex;
  1069.     
  1070.     /* modify the selected paragraphs */
  1071.     
  1072.     HLock((Handle) dp->paragraphs);
  1073.     
  1074.     pp = *dp->paragraphs + startParagraphIndex;
  1075.     paragraphIndex = startParagraphIndex;
  1076.     
  1077.     start = dp->top;
  1078.     end = dp->top + (dp->viewRect.bottom - dp->viewRect.top);
  1079.                 
  1080.     for(;paragraphIndex <= endParagraphIndex; paragraphIndex++, pp++) {
  1081.     
  1082.         firstTime = (paragraphIndex == startParagraphIndex);
  1083.         
  1084.         gxEditGetBitMaskOp(&pp->layoutOptions, options, optionsMask, sizeof(gxLayoutOptions), firstTime);        
  1085.             
  1086.     }
  1087.     
  1088.     /* fix up the mask */
  1089.     
  1090.     if(~optionsMask->width)
  1091.         optionsMask->width = 0;
  1092.     
  1093.     if(~optionsMask->flush)
  1094.         optionsMask->flush = 0;
  1095.     
  1096.     if(~optionsMask->just)
  1097.         optionsMask->just = 0;
  1098.     
  1099.     if(~((long) optionsMask->baselineRec))
  1100.         optionsMask->baselineRec = nil;
  1101.         
  1102.     HUnlock((Handle) dp->paragraphs);
  1103.     
  1104. }
  1105.  
  1106. void DocSetLayoutOptions(DocPtr dp, gxLayoutOptions *options, gxLayoutOptions * optionsMask)
  1107. {
  1108.     ParaPtr            pp;
  1109.     LinePtr            lp;
  1110.     short            startParagraphIndex;
  1111.     short            endParagraphIndex;
  1112.     short            paragraphIndex;
  1113.     short            lineIndex;
  1114.     short            start;
  1115.     short            end;
  1116.     gxLayoutOptions        layoutOptions;
  1117.         
  1118.     /* find the current selected paragraph */
  1119.     
  1120.     startParagraphIndex = dp->selection.startParaIndex;
  1121.     endParagraphIndex = dp->selection.endParaIndex;
  1122.     
  1123.     /* modify the selected paragraphs */
  1124.     
  1125.     HLock((Handle) dp->paragraphs);
  1126.     
  1127.     pp = *dp->paragraphs + startParagraphIndex;
  1128.     paragraphIndex = startParagraphIndex;
  1129.     
  1130.     start = dp->top;
  1131.     end = dp->top + (dp->viewRect.bottom - dp->viewRect.top);
  1132.                 
  1133.     for(;paragraphIndex <= endParagraphIndex; paragraphIndex++, pp++) {
  1134.     
  1135.         /* set the paragraph options */
  1136.                 
  1137.         if(gxEditSetBitMaskOp(options, &pp->layoutOptions, optionsMask, sizeof(gxLayoutOptions))) {
  1138.         
  1139.             pp->width = FixedToInt(pp->layoutOptions.width);
  1140.         
  1141.             /* change all of the layout options of the lines */
  1142.             
  1143.             HLock((Handle) pp->lines);
  1144.             
  1145.             lp = *pp->lines;
  1146.             
  1147.             for(lineIndex=0; lineIndex < pp->numLines; lineIndex++, lp++) {
  1148.             
  1149.                 if(lineIndex == pp->numLines - 1) {
  1150.                     layoutOptions = pp->layoutOptions;
  1151.                     layoutOptions.just = gxNoJustification;
  1152.                     GXSetLayout(lp->layout, 0, nil, nil, 0, nil, nil, 0, nil, nil, &layoutOptions, nil);
  1153.                 } else
  1154.                     GXSetLayout(lp->layout, 0, nil, nil, 0, nil, nil, 0, nil, nil, &pp->layoutOptions, nil);
  1155.                     
  1156.                 lp->drawn = false;
  1157.             }
  1158.             
  1159.             HUnlock((Handle) pp->lines);
  1160.         
  1161.             /* now redraw the paragraph if it is displayed on the screen */
  1162.             
  1163.             if(pp->start + GetParagraphHeight(dp, pp) >= start || pp->start < end)
  1164.                 DrawParagraph(dp, pp, start, end);
  1165.         }
  1166.         
  1167.     }
  1168.     
  1169.     gxEditSetBitMaskOp(options, &dp->currentLayoutOptions, optionsMask, sizeof(gxLayoutOptions));
  1170.     
  1171.     HUnlock((Handle) dp->paragraphs);
  1172.     
  1173. }
  1174.  
  1175. void DocPrint(DocPtr dp, gxJob printJob)
  1176. {
  1177.     short            numPages;
  1178.     long                ** pageStarts;
  1179.     short            page;
  1180.     OSErr            err;
  1181.     gxViewPort        aViewPort;
  1182.     gxShape            picture;
  1183.  
  1184.     aViewPort = dp->docViewPort;
  1185.     
  1186.     CalcPrintPages(dp, printJob, &numPages, &pageStarts);
  1187.     
  1188.     /* document title should be used !!! */
  1189.     
  1190.     GXStartJob(printJob, "\pGX Edit Doc", numPages);
  1191.     
  1192.     if((err = GXGetJobError(printJob)) != noErr)
  1193.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  1194.     
  1195.     for(page=0; page<numPages; page++) {
  1196.         
  1197.         picture = GetAPage(dp, (*pageStarts)[page]);
  1198.         
  1199.         GXPrintPage(printJob,  page+1, GXGetJobFormat((gxJob) printJob, 1), picture);
  1200.                 
  1201.         if((err = GXGetJobError((gxJob) printJob)) != noErr)
  1202.             gxEditPostError(dp, gx_edit_internal_fatal_error);
  1203.             
  1204.         GXDisposeShape(picture);
  1205.         
  1206.     }
  1207.     
  1208.     GXFinishJob(printJob);
  1209.     
  1210.     if((err =GXGetJobError(printJob)) != noErr)
  1211.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  1212.         
  1213.     DisposeHandle((Handle) pageStarts);
  1214. }
  1215.  
  1216. void DocCopy(DocPtr dp)
  1217. {
  1218.  
  1219.     Copy(dp);
  1220.     
  1221. }
  1222.  
  1223.  
  1224. void DocPaste(DocPtr dp)
  1225. {
  1226.     
  1227.     Paste(dp);
  1228.     
  1229.     /* reflow the document */
  1230.     
  1231.     while(DocReflow(dp)) ;
  1232.     
  1233.     CheckCaretVisibility(dp);
  1234.     
  1235.     Draw(dp, 0, dp->viewHeight);
  1236.         
  1237. }
  1238.  
  1239. long DocGetScrapLen(DocPtr dp)
  1240. {
  1241.     return(dp->scrap.numText);
  1242. }
  1243.  
  1244. long DocGetSelectionLen(DocPtr dp)
  1245. {
  1246.     return(dp->selection.endDocOffset - dp->selection.startDocOffset);
  1247. }
  1248.  
  1249. long DocGetTextLen(DocPtr dp)
  1250. {
  1251.     return(dp->numText);
  1252. }
  1253.  
  1254. Boolean DocIdle(DocPtr dp)
  1255. {
  1256.     Boolean            modified;
  1257.     
  1258.     dp->currentTime = TickCount();
  1259.     
  1260.     BlinkCursor(dp);
  1261.     
  1262.     if(modified = DocReflow(dp)) {
  1263.  
  1264.         CheckCaretVisibility(dp);
  1265.     
  1266.         Draw(dp, 0, dp->viewHeight);
  1267.         
  1268.     }
  1269.     
  1270.     return(modified);
  1271.         
  1272. }
  1273.  
  1274. void DocSetVerticalText(DocPtr dp, Boolean enable)
  1275. {
  1276.     ParaPtr            pp;
  1277.     StylePtr            sp;
  1278.     LinePtr            lp;
  1279.     short            i, j;
  1280.     gxTextAttribute    attributes;
  1281.     
  1282.     if(dp->verticalText != enable) {
  1283.     
  1284.         dp->verticalText = enable;
  1285.         
  1286.         if(dp->verticalText) {
  1287.             dp->lineWidth = dp->viewRect.bottom - dp->viewRect.top - dp->leftMargin - dp->rightMargin;
  1288.             dp->viewHeight = dp->viewRect.right - dp->viewRect.left;
  1289.         } else {
  1290.             dp->lineWidth = dp->viewRect.right - dp->viewRect.left - dp->leftMargin - dp->rightMargin;
  1291.             dp->viewHeight = dp->viewRect.bottom - dp->viewRect.top;
  1292.         }
  1293.         
  1294.         /* set all paragraph widths to the new line width value */
  1295.         
  1296.         pp = *dp->paragraphs;
  1297.         
  1298.         for(i=0; i<dp->numParagraphs; i++, pp++) {
  1299.         
  1300.             pp->width = dp->lineWidth;
  1301.             pp->layoutOptions.width = ff(pp->width);
  1302.  
  1303.             if(pp->numLines) {
  1304.             
  1305.                 pp->reflow = true;
  1306.                 (*pp->lines)[0].reflow = true;
  1307.                 
  1308.             }
  1309.         }
  1310.         
  1311.         /* change all existing styles to have the correct text attribute */
  1312.         
  1313.         sp = *dp->styles;
  1314.         for(i=0; i<dp->numStyles;i++,sp++) {
  1315.             attributes = GXGetStyleTextAttributes(sp->textStyle);
  1316.             
  1317.             if(enable)
  1318.                 attributes |= gxVerticalText;
  1319.             else
  1320.                 attributes &= ~gxVerticalText;
  1321.                 
  1322.             GXSetStyleTextAttributes(sp->textStyle, attributes);
  1323.         }
  1324.         
  1325.         /* mark everything dirty */
  1326.         
  1327.         for(i=0, pp = *dp->paragraphs; i<dp->numParagraphs;i++, pp++) {
  1328.             for(j=0, lp = *pp->lines; j<pp->numLines; j++, lp++)
  1329.                 lp->dirty = true;
  1330.             pp->dirty = true;
  1331.         }
  1332.         dp->dirty = true;
  1333.         
  1334.         /* mark the entire document as not drawn */
  1335.         dp->drawn = false;
  1336.     
  1337.         /* make sure we clear the entire document white area */
  1338.         if(dp->verticalText)
  1339.             dp->bottomClear = dp->viewRect.left;
  1340.         else
  1341.             dp->bottomClear = dp->viewRect.bottom;
  1342.         
  1343.     } 
  1344.  
  1345. }
  1346.  
  1347. void DocGetVerticalText(DocPtr dp, Boolean * enable)
  1348. {
  1349.     *enable = dp->verticalText;
  1350. }
  1351.  
  1352. void DocGetSelectionEncoding(DocPtr dp, gxFontPlatform * platformPtr, gxFontScript * scriptPtr, gxFontLanguage * languagePtr)
  1353. {
  1354.     short            i;
  1355.     gxFontPlatform        platform;
  1356.     gxFontScript        script;
  1357.     gxFontLanguage        language;
  1358.     gxStyle            style;
  1359.     gxFontPlatform        nextPlatform;
  1360.     gxFontScript        nextScript;
  1361.     gxFontLanguage        nextLanguage;
  1362.     
  1363.     if(!dp->numCurrentStyles) {
  1364.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  1365.         return;
  1366.     }
  1367.     
  1368.     style = GetDocStyle(dp, (*dp->currentStyles)[0])->textStyle;
  1369.     
  1370.     platform = GXGetStyleEncoding(style, &script, &language);
  1371.     
  1372.     for(i=0; i < dp->numCurrentStyles; i++) {
  1373.     
  1374.         style = GetDocStyle(dp, (*dp->currentStyles)[i])->textStyle;
  1375.         
  1376.         nextPlatform = GXGetStyleEncoding(style, &nextScript, &nextLanguage);
  1377.         
  1378.         if(nextPlatform != platform)
  1379.             platform = gxNoPlatform;
  1380.             
  1381.         if(nextScript != script)
  1382.             script = gxNoScript;
  1383.             
  1384.         if(nextLanguage != language)
  1385.             language = gxNoLanguage;
  1386.             
  1387.     }
  1388.     
  1389.     if(platformPtr != nil)  *platformPtr = platform;
  1390.     if(scriptPtr != nil)  *scriptPtr = script;
  1391.     if(languagePtr != nil)  *languagePtr = language;
  1392.         
  1393. }
  1394.  
  1395. void DocSetSelectionEncoding(DocPtr dp, gxFontPlatform platform, gxFontScript script, gxFontLanguage language)
  1396. {
  1397.     short            * newStyles;
  1398.     short            i;
  1399.     
  1400.     if(dp->numCurrentStyles != 0) {
  1401.     
  1402.         newStyles = (short *) NewPtr(dp->numCurrentStyles * sizeof(short));
  1403.         
  1404.         HLock((Handle) dp->currentStyles);
  1405.         
  1406.         for(i=0; i<dp->numCurrentStyles; i++)
  1407.             newStyles[i] = SetDocStyleEncoding(dp, (*dp->currentStyles)[i], platform, script, language);
  1408.             
  1409.         if(SetSelectionStyles(dp, dp->numCurrentStyles, *dp->currentStyles, newStyles))
  1410.             CalcPositionAndDraw(dp, dp->selection.startParaIndex);
  1411.  
  1412.         HUnlock((Handle) dp->currentStyles);
  1413.         
  1414.         DisposePtr((Ptr) newStyles);
  1415.             
  1416.         SetSelection(dp, dp->selection.startDocOffset, dp->selection.endDocOffset, false, dp->selection.endOfLine, false);
  1417.         
  1418.     } else
  1419.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  1420.  
  1421. }
  1422.  
  1423. static void CalcPrintPages(DocPtr dp, gxJob printJob, short * numPagesPtr, long *** pageStartsPtr)
  1424. {
  1425.     short                numPages;
  1426.     long                ** pageStarts;
  1427.     ParaPtr                pp;
  1428.     LinePtr                lp;
  1429.     short                paragraphIndex;
  1430.     short                lineIndex;
  1431.     short                top;
  1432.     short                bottom;
  1433.     long                    docOffset;
  1434.     gxFormat                format;
  1435.     gxRectangle            pageSize;
  1436.     gxRectangle            paperSize;
  1437.  
  1438.     numPages = 0;
  1439.     pageStarts = (long **) NewHandle(0);
  1440.     
  1441.     /* calculate the page dimensions */
  1442.     
  1443.     format = GXGetJobFormat((gxJob) printJob, 1);
  1444.     GXGetFormatDimensions(format, &pageSize, &paperSize);
  1445.     
  1446.     dp->pageTop = FixedToInt(paperSize.top) + kPrintTopMargin;
  1447.     dp->pageLeft = FixedToInt(paperSize.left) + kPrintLeftMargin;
  1448.     dp->pageBottom = FixedToInt(paperSize.bottom) - kPrintBottomMargin;
  1449.     dp->pageRight = FixedToInt(paperSize.right) - kPrintRightMargin;
  1450.         
  1451.     HLock((Handle) dp->paragraphs);
  1452.     
  1453.     pp = *dp->paragraphs;
  1454.     
  1455.     if(dp->verticalText) {
  1456.     
  1457.         /* layout left to right for now,  we only need to see what layous fit */
  1458.         
  1459.         top = dp->pageLeft;
  1460.         bottom = dp->pageRight;
  1461.         
  1462.     } else {
  1463.         top = dp->pageTop;
  1464.         bottom = dp->pageBottom;
  1465.     }
  1466.     
  1467.     docOffset = 0;
  1468.     
  1469.     for(paragraphIndex = 0; paragraphIndex < dp->numParagraphs; paragraphIndex++, pp++) {
  1470.     
  1471.         HLock((Handle) pp->lines);
  1472.         
  1473.         lp = *pp->lines;
  1474.         
  1475.         for(lineIndex = 0; lineIndex < pp->numLines; lineIndex++, lp++) {
  1476.         
  1477.             if(top + GetLineHeight(dp, pp, lp)  > bottom) {
  1478.             
  1479.                 PtrAndHand((Ptr) &docOffset, (Handle) pageStarts, sizeof(long));
  1480.                 docOffset = lp->paraOffset + pp->docOffset;
  1481.                 top = dp->pageTop;
  1482.                 numPages++;
  1483.             
  1484.             }
  1485.             
  1486.             top += lp->height;
  1487.             
  1488.         }
  1489.         
  1490.         HUnlock((Handle) pp->lines);
  1491.         
  1492.     }
  1493.     
  1494.     HUnlock((Handle) dp->paragraphs);
  1495.  
  1496.     PtrAndHand((Ptr) &docOffset, (Handle) pageStarts, sizeof(long));
  1497.     numPages++;
  1498.     
  1499.     *pageStartsPtr = pageStarts;
  1500.     *numPagesPtr = numPages;
  1501. }
  1502.  
  1503. static gxShape GetAPage(DocPtr dp, long docOffset)
  1504. {
  1505.     ParaPtr            pp;
  1506.     LinePtr            lp;
  1507.     gxShape            picture;
  1508.     short            top;
  1509.     short            bottom;
  1510.     short            left;
  1511.     short            right;
  1512.     fixed                fixedLeft;
  1513.     fixed                fixedTop;
  1514.     short            paragraphIndex;
  1515.     short            lineIndex;
  1516.     short            paraOffset;
  1517.     long                numLayouts;
  1518.     void                ** layouts;
  1519.     
  1520.     layouts = (void **) NewHandle(0);
  1521.     numLayouts = 0;
  1522.     
  1523.     HLock((Handle) dp->paragraphs);
  1524.     
  1525.     pp = *dp->paragraphs;
  1526.     
  1527.     for(paragraphIndex = 0; paragraphIndex < dp->numParagraphs; paragraphIndex++, pp++)
  1528.         if(pp->docOffset + pp->numText > docOffset)
  1529.             break;
  1530.     
  1531.     if(paragraphIndex == dp->numParagraphs)
  1532.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  1533.         
  1534.     HLock((Handle) pp->lines);
  1535.     
  1536.     lp = *pp->lines;
  1537.     paraOffset = docOffset - pp->docOffset;
  1538.     
  1539.     for(lineIndex = 0; lineIndex < pp->numLines; lineIndex++, lp++)
  1540.         if(lp->paraOffset + lp->numText > paraOffset)
  1541.             break;
  1542.             
  1543.     if(lineIndex == pp->numLines)
  1544.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  1545.         
  1546.     if(dp->verticalText) {
  1547.     
  1548.         left = dp->pageLeft;
  1549.         right = dp->pageRight;
  1550.         
  1551.         fixedTop = ff(dp->pageTop);
  1552.     
  1553.         while(right - GetLineHeight(dp, pp, lp) > left) {
  1554.         
  1555.             fixedLeft = ff(right - lp->ascent);
  1556.             
  1557.             if(lp->layoutPos.x != fixedLeft || lp->layoutPos.y != fixedTop) {
  1558.             
  1559.                 GXMoveShapeTo((gxShape) lp->layout, fixedLeft, fixedTop);
  1560.     
  1561.                 lp->layoutPos.x = fixedLeft;
  1562.                 lp->layoutPos.y = fixedTop;
  1563.                 
  1564.             }
  1565.             
  1566.             PtrAndHand((Ptr) &lp->layout, (Handle) layouts, sizeof(void *));
  1567.             
  1568.             right -= lp->height;
  1569.             
  1570.             lineIndex++;
  1571.             lp++;
  1572.             
  1573.             if(lineIndex == pp->numLines) {
  1574.             
  1575.                 paragraphIndex++;
  1576.                 
  1577.                 if(paragraphIndex == dp->numParagraphs)
  1578.                     break;
  1579.     
  1580.                 HUnlock((Handle) pp->lines);
  1581.                 
  1582.                 pp++;
  1583.                 
  1584.                 HLock((Handle) pp->lines);
  1585.                 
  1586.                 lp = *pp->lines;
  1587.                 lineIndex = 0;
  1588.                 
  1589.             }
  1590.             
  1591.         }
  1592.         
  1593.     } else {
  1594.     
  1595.         top = dp->pageTop;
  1596.         bottom = dp->pageBottom;
  1597.         
  1598.         fixedLeft = ff(dp->pageLeft);
  1599.     
  1600.         while(top + GetLineHeight(dp, pp, lp) < bottom) {
  1601.         
  1602.             fixedTop = ff(top + lp->ascent);
  1603.             
  1604.             if(lp->layoutPos.x != fixedLeft || lp->layoutPos.y != fixedTop) {
  1605.             
  1606.                 GXMoveShapeTo((gxShape) lp->layout, fixedLeft, fixedTop);
  1607.     
  1608.                 lp->layoutPos.x = fixedLeft;
  1609.                 lp->layoutPos.y = fixedTop;
  1610.                 
  1611.             }
  1612.             
  1613.             PtrAndHand((Ptr) &lp->layout, (Handle) layouts, sizeof(void *));
  1614.             
  1615.             top += lp->height;
  1616.             
  1617.             lineIndex++;
  1618.             lp++;
  1619.             
  1620.             if(lineIndex == pp->numLines) {
  1621.             
  1622.                 paragraphIndex++;
  1623.                 
  1624.                 if(paragraphIndex == dp->numParagraphs)
  1625.                     break;
  1626.     
  1627.                 HUnlock((Handle) pp->lines);
  1628.                 
  1629.                 pp++;
  1630.                 
  1631.                 HLock((Handle) pp->lines);
  1632.                 
  1633.                 lp = *pp->lines;
  1634.                 lineIndex = 0;
  1635.                 
  1636.             }
  1637.             
  1638.         }
  1639.     }
  1640.     
  1641.     HUnlock((Handle) pp->lines);
  1642.     
  1643.     HUnlock((Handle) dp->paragraphs);
  1644.     
  1645.     numLayouts = GetHandleSize((Handle) layouts) / sizeof(void *);
  1646.     
  1647.     HLock((Handle) layouts);
  1648.     
  1649.     picture = GXNewPicture(numLayouts, *layouts, nil, nil, nil);
  1650.     
  1651.     HUnlock((Handle) layouts);
  1652.     
  1653.     DisposeHandle((Handle) layouts);
  1654.         
  1655.     return(picture);
  1656.  
  1657. }
  1658.  
  1659. static void CalcOffsets(DocPtr dp, short paragraphIndex)
  1660. {
  1661.     ParaPtr            pp;
  1662.     short            docOffset;
  1663.     
  1664.     if(paragraphIndex < 0 || paragraphIndex > dp->numParagraphs)
  1665.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  1666.         
  1667.     pp = *dp->paragraphs + paragraphIndex;
  1668.     
  1669.     if(paragraphIndex == 0)
  1670.         pp->docOffset = 0;
  1671.     else {
  1672.         paragraphIndex--;
  1673.         pp--;
  1674.     }
  1675.  
  1676.     docOffset = pp->docOffset + pp->numText;
  1677.     
  1678.     paragraphIndex++;
  1679.     pp++;
  1680.     
  1681.     for(;paragraphIndex < dp->numParagraphs; paragraphIndex++, pp++) {
  1682.         pp->docOffset = docOffset;
  1683.         docOffset += pp->numText;
  1684.     }
  1685.         
  1686.     dp->numText = docOffset;
  1687.     
  1688. }
  1689.  
  1690. static void CalcStarts(DocPtr dp, short paragraphIndex)
  1691. {
  1692.     ParaPtr            pp;
  1693.     long                start;
  1694.     
  1695.     if(paragraphIndex < 0 || paragraphIndex > dp->numParagraphs)
  1696.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  1697.     
  1698.     HLock((Handle) dp->paragraphs);
  1699.     
  1700.     pp = *dp->paragraphs + paragraphIndex;
  1701.     
  1702.     if(paragraphIndex == 0) {
  1703.     
  1704.         if(pp->start != 0)
  1705.             pp->drawn = false;
  1706.             
  1707.         pp->start = 0;
  1708.         
  1709.     } else {
  1710.     
  1711.         paragraphIndex--;
  1712.         pp--;
  1713.     }
  1714.  
  1715.     start = pp->start + GetParagraphHeight(dp, pp);
  1716.     
  1717.     paragraphIndex++;
  1718.     pp++;
  1719.     
  1720.     for(;paragraphIndex < dp->numParagraphs; paragraphIndex++, pp++) {
  1721.     
  1722.         if(pp->start != start)
  1723.             pp->drawn = false;        /* the paragraph has moved -- redraw */
  1724.         
  1725.         pp->start = start;
  1726.  
  1727.         start += GetParagraphHeight(dp, pp);
  1728.         
  1729.     }
  1730.         
  1731.     HUnlock((Handle) dp->paragraphs);
  1732.     
  1733.     dp->length = start;
  1734.     dp->dirty = false;
  1735.     
  1736.     DocSetMaxTop(dp);
  1737.     
  1738. }
  1739.  
  1740. static void InsertNewParagraph(DocPtr dp, short paragraphIndex, short paragraphOffset)
  1741. {
  1742.     ParaRec        newPara;
  1743.     ParaPtr        pp;
  1744.     long        size;
  1745.     
  1746.     HLock((Handle) dp->paragraphs);
  1747.     
  1748.     pp = *dp->paragraphs + paragraphIndex;
  1749.         
  1750.     SplitParagraph(dp, pp, paragraphOffset, &newPara);
  1751.     
  1752.     HUnlock((Handle) dp->paragraphs);
  1753.     
  1754.     dp->numParagraphs++;
  1755.     
  1756.     SetHandleSize((Handle) dp->paragraphs, dp->numParagraphs * sizeof(ParaRec));
  1757.     
  1758.     size = sizeof(ParaRec) * (dp->numParagraphs - paragraphIndex - 2);
  1759.     
  1760.     BlockMove((Ptr) (*dp->paragraphs + paragraphIndex + 1),
  1761.               (Ptr) (*dp->paragraphs + paragraphIndex + 2), size);
  1762.               
  1763.     BlockMove((Ptr) &newPara, (Ptr) (*dp->paragraphs + paragraphIndex + 1), sizeof(ParaRec));
  1764.         
  1765. }
  1766.  
  1767. void DocSetMaxTop(DocPtr dp)
  1768. {
  1769.     short        dv;
  1770.     
  1771.     dp->maxTop = DocHeight(dp) - dp->viewHeight;
  1772.     
  1773.     if(dp->maxTop < 0)
  1774.         dp->maxTop = 0;
  1775.         
  1776.     if(dp->top > dp->maxTop) {
  1777.     
  1778.         dv = dp->top - dp->maxTop;
  1779.         
  1780.         DocScroll(dp, dv);
  1781.             
  1782.     }
  1783. }
  1784.  
  1785. void DocProof(DocPtr dp, GXEditProofPtr proof)
  1786. {
  1787.     long                startParaIndex;
  1788.     long                pointSize;
  1789.     ReplacementRec    replacements;
  1790.     long                startOffset;
  1791.     
  1792.     if(dp->selection.startDocOffset == dp->selection.endDocOffset)
  1793.         return;        /* nothing to proof */
  1794.  
  1795.     Copy(dp);
  1796.     Clear(dp);
  1797.  
  1798.     startParaIndex = dp->selection.startParaIndex;
  1799.     
  1800.     /* generate the text to waterfall */
  1801.     
  1802.     startOffset = dp->selection.startDocOffset;
  1803.     
  1804.     NewReplacements(dp, proof,  &replacements);
  1805.     
  1806.     do {
  1807.     
  1808.         DoReplacements(&replacements);
  1809.  
  1810.         Paste(dp);
  1811.                 
  1812.     } while(!TestReplacements(&replacements));
  1813.     
  1814.     SetSelection(dp, startOffset, dp->selection.endDocOffset, false, dp->selection.endOfLine, false);
  1815.     
  1816.     Copy(dp);
  1817.     Clear(dp);
  1818.     
  1819.     /* generate the waterfall */
  1820.  
  1821.     pointSize = proof->startPointSize;
  1822.     
  1823.     while(pointSize <= proof->endPointSize) {
  1824.     
  1825.         Paste(dp);
  1826.         
  1827.         SetSelection(dp, dp->selection.endDocOffset - dp->scrap.numText, dp->selection.endDocOffset, false, dp->selection.endOfLine, false);
  1828.  
  1829.         DocSetTextSize(dp, pointSize);
  1830.                 
  1831.         SetSelection(dp, dp->selection.endDocOffset, dp->selection.endDocOffset, false, dp->selection.endOfLine, false);
  1832.  
  1833.         pointSize += proof->stepPointSize;
  1834.     }
  1835.     
  1836.     DisposeReplacements( &replacements);
  1837.     
  1838.     CalcOffsets(dp, startParaIndex);
  1839.     
  1840.     dp->dirty = true;                    /* CalcStarts(dp, startParaIndex); */
  1841.  
  1842.     /* reflow the document */
  1843.     
  1844.     while(DocReflow(dp)) ;
  1845.     
  1846.     CheckCaretVisibility(dp);
  1847.  
  1848.     Draw(dp, 0, dp->viewHeight);
  1849.         
  1850. }
  1851.  
  1852. void DocActivate(DocPtr dp, Boolean activate)
  1853. {
  1854.  
  1855.     if(activate) {
  1856.         gxEditScrapFromDesk(dp);
  1857.     } else {
  1858.         gxEditScrapToDesk(dp);
  1859.     }
  1860.     
  1861. }
  1862.  
  1863. void DocSetEncoding(DocPtr dp, gxFontPlatform platform, gxFontScript script, gxFontLanguage language)
  1864. {
  1865.     dp->currentPlatform = platform;
  1866.     dp->currentScript = script;
  1867.     dp->currentLanguage = language;
  1868. }
  1869.  
  1870. static void InitRunControl(gxRunControls * runControl)
  1871. {
  1872.  
  1873.     runControl->flags = 0;        /* all off id the default state */
  1874.     runControl->beforeWithStreamShift = ff(0);
  1875.     runControl->afterWithStreamShift = ff(0);
  1876.     runControl->crossStreamShift = ff(0);
  1877.     runControl->imposedWidth = ff(0);
  1878.     runControl->track = gxNoTracking;
  1879.     runControl->hangingInhibitFactor = fract1;
  1880.     runControl->kerningInhibitFactor = fract1;
  1881.     runControl->decompositionAdjustmentFactor = ff(0);
  1882.     runControl->baselineType = 0;        /* roman baseline */
  1883.  
  1884. }
  1885.  
  1886. static void BlinkCursor(DocPtr dp)
  1887. {
  1888.     if(dp->selection.startDocOffset != dp->selection.endDocOffset)
  1889.         return;        /* selection range is not a cursor */
  1890.         
  1891.     /* code to blink cursor */    
  1892. }
  1893.  
  1894. Boolean DocReflow(DocPtr dp)
  1895. {
  1896.     ParaPtr        pp;
  1897.     short        paragraphIndex;
  1898.     
  1899.     /* try to find a paragraph that needs to be reflowed */
  1900.     
  1901.     HLock((Handle) dp->paragraphs);
  1902.     
  1903.     pp = *dp->paragraphs;
  1904.     
  1905.     for(paragraphIndex=0; paragraphIndex < dp->numParagraphs; paragraphIndex++, pp++)
  1906.         if(pp->reflow) {
  1907.         
  1908.             ReflowParagraph(dp, pp);
  1909.             
  1910.             HUnlock((Handle) dp->paragraphs);
  1911.             
  1912.             CalcOffsets(dp, paragraphIndex);
  1913.             
  1914.             dp->dirty = true;                    /* CalcStarts(dp, paragraphIndex); */
  1915.  
  1916.             return(true);
  1917.         }
  1918.         
  1919.     HUnlock((Handle) dp->paragraphs);
  1920. }
  1921.  
  1922. static void CalcPositionAndDraw(DocPtr dp,short startIndex)        
  1923.  {
  1924.     /* calculate starts and offsets -- set document height */
  1925.     CalcOffsets(dp, startIndex);
  1926.     dp->dirty = true;                            /* CalcStarts(dp, startIndex); */
  1927.     CheckCaretVisibility(dp);
  1928.     Draw(dp, 0, dp->viewHeight);
  1929. }
  1930.  
  1931. static void Position(DocPtr dp, long docOffset, long * start, long * end)
  1932. {
  1933.     ParaPtr        pp;
  1934.     short        paragraphIndex;
  1935.     short        paragraphOffset;
  1936.         
  1937.     if(dp->dirty)        /* we are using paragraph starts, make sure document is not dirty */
  1938.         CalcStarts(dp, 0);
  1939.     
  1940.     GetParagraphIndexAndOffset(dp, docOffset, ¶graphIndex, ¶graphOffset, false);
  1941.     
  1942.     HLock((Handle) dp->paragraphs);
  1943.     
  1944.     pp = *dp->paragraphs + paragraphIndex;
  1945.     
  1946.     ParagraphPosition(dp, pp, paragraphOffset, start, end);
  1947.     
  1948.     *start += pp->start;
  1949.     *end += pp->start;
  1950.         
  1951.     HUnlock((Handle) dp->paragraphs);
  1952.     
  1953. }
  1954.  
  1955. static void Draw(DocPtr dp, long start, long end)
  1956. {
  1957.     ParaPtr            pp;
  1958.     short            paragraphIndex;
  1959.         
  1960.     if(start > end)
  1961.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  1962.         
  1963.     if(start < 0)
  1964.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  1965.     
  1966.     if(end < 0)
  1967.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  1968.     
  1969.     if(start > dp->viewHeight)
  1970.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  1971.  
  1972.     if(end > dp->viewHeight)
  1973.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  1974.         
  1975.     if(dp->dirty)        /* we are using paragraph starts, make sure document is not dirty */
  1976.         CalcStarts(dp, 0);
  1977.     
  1978.     HLock((Handle) dp->paragraphs);
  1979.     
  1980.     /* map the view area coords to doc coords */
  1981.     
  1982.     start +=  dp->top;
  1983.     end +=  dp->top;
  1984.                 
  1985.     /* loop through all of the paragraphs, draw paragraphs that fall in the range */
  1986.     
  1987.     /* this loop should be optimized in the future */
  1988.     
  1989.     pp = *dp->paragraphs;
  1990.     
  1991.     for(paragraphIndex=0; paragraphIndex < dp->numParagraphs; pp++, paragraphIndex++) {
  1992.                     
  1993.         if((pp->start + GetParagraphHeight(dp, pp)) >= start && (pp->start < end)) {
  1994.                        
  1995.             DrawParagraph(dp, pp, start, end);
  1996.             
  1997.         } else {
  1998.         
  1999.             pp->drawn = false;
  2000.  
  2001.         }
  2002.         
  2003.     }
  2004.     
  2005.     /* erase from the last paragraph to end of view if necessary */
  2006.     
  2007.     
  2008.     if(paragraphIndex == dp->numParagraphs) 
  2009.         DoEraseToEndOfView(dp);
  2010.         
  2011.         
  2012.     dp->drawn = true;
  2013.         
  2014.     HUnlock((Handle) dp->paragraphs);
  2015.         
  2016. }
  2017.  
  2018. static void HitTest(DocPtr dp, Point where, long * docOffsetPtr, Boolean * endOfLinePtr, Boolean extend)
  2019. {
  2020.     ParaPtr                pp;
  2021.     long                    docOffset;
  2022.     short                paraIndex;
  2023.     short                paraOffset;
  2024.     Boolean                endOfLine;
  2025.     
  2026.     if(dp->dirty)        /* we are using paragraph starts, make sure document is not dirty */
  2027.         CalcStarts(dp, 0);
  2028.     
  2029.     if(dp->verticalText) {
  2030.     
  2031.         if(where.h > dp->viewRect.right)
  2032.             where.h = dp->viewRect.right;
  2033.             
  2034.         if(where.h < dp->viewRect.left)
  2035.             where.h = dp->viewRect.left;
  2036.             
  2037.         where.h = dp->viewRect.right - where.h;
  2038.         
  2039.         where.v -= dp->viewRect.top + dp->leftMargin;
  2040.         
  2041.     } else {
  2042.     
  2043.         if(where.v < dp->viewRect.top)
  2044.             where.v = dp->viewRect.top;
  2045.         
  2046.         if(where.v > dp->viewRect.bottom)
  2047.             where.v = dp->viewRect.bottom;
  2048.         
  2049.         where.v -= dp->viewRect.top;
  2050.         
  2051.         where.h -= dp->viewRect.left + dp->leftMargin;
  2052.             
  2053.          where.v += dp->top;
  2054.          
  2055.      }
  2056.          
  2057.     HLock((Handle) dp->paragraphs);
  2058.     
  2059.     /* find the paragraph and hit test paragraph */
  2060.     
  2061.     pp = *dp->paragraphs;
  2062.     docOffset = 0;
  2063.     
  2064.     if(dp->verticalText) {
  2065.         for(paraIndex=0; paraIndex < dp->numParagraphs; paraIndex++,pp++)
  2066.             if(where.h >= pp->start && where.h < (pp->start + GetParagraphHeight(dp, pp))) {
  2067.             
  2068.                 where.h -= pp->start;
  2069.                 
  2070.                 HitTestParagraph(dp, pp, where, ¶Offset, &endOfLine);
  2071.                 
  2072.                 if(!extend && paraOffset == pp->numText) {
  2073.                     paraOffset--;
  2074.                     endOfLine = false;
  2075.                 }
  2076.                 
  2077.                 docOffset =  paraOffset + pp->docOffset;
  2078.                 break;
  2079.                 
  2080.             }
  2081.     } else {
  2082.         for(paraIndex=0; paraIndex < dp->numParagraphs; paraIndex++,pp++)
  2083.             if(where.v >= pp->start && where.v < (pp->start + GetParagraphHeight(dp, pp))) {
  2084.             
  2085.                 where.v -= pp->start;
  2086.                 
  2087.                 HitTestParagraph(dp, pp, where, ¶Offset, &endOfLine);
  2088.                 
  2089.                 if(!extend && paraOffset == pp->numText) {
  2090.                     paraOffset--;
  2091.                     endOfLine = false;
  2092.                 }
  2093.                 
  2094.                 docOffset =  paraOffset + pp->docOffset;
  2095.                 break;
  2096.                 
  2097.             }
  2098.     }
  2099.         
  2100.     if(paraIndex == dp->numParagraphs && dp->numParagraphs != 0)
  2101.         docOffset = (pp-1)->docOffset + (pp-1)->numText;
  2102.     
  2103.     HUnlock((Handle) dp->paragraphs);
  2104.     
  2105.     *docOffsetPtr = docOffset;
  2106.     *endOfLinePtr = endOfLine;
  2107.     
  2108. }
  2109.  
  2110. static void Insert(DocPtr dp, void * text, short startNumText, short styleIndex)
  2111. {
  2112.     short        paragraphIndex, paragraphOffset;
  2113.     ParaPtr        pp;
  2114.     short        numParaText;
  2115.     char            * ptr;
  2116.     short        startIndex;
  2117.     short        startOffset;
  2118.     short        newParagraphs;
  2119.     long            docOffset;
  2120.     short        numText;
  2121.     StylePtr        style;
  2122.     Boolean        setEmptyStyle;
  2123.     
  2124.     Clear(dp);
  2125.         
  2126.     if(dp->numCurrentStyles == 0)
  2127.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  2128.  
  2129.     /* find the paragraph index and offset from the current selection start */
  2130.     
  2131.     paragraphIndex = dp->selection.startParaIndex;
  2132.     paragraphOffset = dp->selection.startParaOffset;
  2133.     
  2134.     numText = startNumText;
  2135.     
  2136.     if(numText == 0)
  2137.         return;
  2138.     
  2139.     HLock((Handle) dp->paragraphs);
  2140.     
  2141.     startIndex = paragraphIndex;
  2142.     startOffset = paragraphOffset;
  2143.     newParagraphs = 0;
  2144.         
  2145.     style = GetDocStyle(dp, styleIndex);
  2146.     
  2147.     if(style->platform != gxGlyphPlatform) {
  2148.     
  2149.         /* insert all characters up to the newline character */
  2150.     
  2151.         for(numParaText=0, ptr=(char *) text; numParaText<numText; numParaText++, ptr++)
  2152.             if(*ptr == '\r')
  2153.                 break;
  2154.                 
  2155.     } else
  2156.         numParaText = numText;    
  2157.     
  2158.     if(numParaText) {
  2159.     
  2160.         pp = *dp->paragraphs + paragraphIndex;
  2161.         
  2162.         InsertParagraphText(dp, pp, paragraphOffset, text, numParaText, styleIndex);
  2163.         
  2164.         numText -= numParaText;
  2165.         text = (void *) ((long) text + numParaText );
  2166.         paragraphOffset += numParaText;
  2167.         
  2168.     }
  2169.     
  2170.     /* now add new paragraphs as appropriate */
  2171.     
  2172.     while(numText) {
  2173.     
  2174.         text = (void *) ((long) text + 1);
  2175.         numText--;            /* skip past newline */
  2176.     
  2177.         for(numParaText=0, ptr=(char *) text; numParaText<numText; numParaText++, ptr++)
  2178.             if(*ptr == '\r')
  2179.                 break;            
  2180.                 
  2181.         HUnlock((Handle) dp->paragraphs);
  2182.         
  2183.         InsertNewParagraph(dp, paragraphIndex, paragraphOffset);
  2184.         
  2185.         newParagraphs++;
  2186.         
  2187.         paragraphIndex++;
  2188.         paragraphOffset = 0;
  2189.         
  2190.         HLock((Handle) dp->paragraphs);
  2191.         
  2192.         if(numParaText) {
  2193.         
  2194.             pp = *dp->paragraphs + paragraphIndex;
  2195.             
  2196.             InsertParagraphText(dp, pp, 0, text, numParaText,  styleIndex);
  2197.             
  2198.             numText -= numParaText;
  2199.             text = (void *) ((long) text + numParaText);
  2200.             paragraphOffset += numParaText;
  2201.             
  2202.         }
  2203.     
  2204.         
  2205.     }
  2206.     
  2207.     HUnlock((Handle) dp->paragraphs);
  2208.     
  2209.     /* calculate starts and offsets -- set document height */
  2210.     
  2211.     CalcOffsets(dp, startIndex);
  2212.     
  2213.     dp->dirty = true;                        /* CalcStarts(dp, startIndex); */
  2214.     
  2215.     /* update the current selection */
  2216.     
  2217.     docOffset = dp->selection.startDocOffset + startNumText;
  2218.     
  2219.     /* should we set the empty style? */
  2220.     setEmptyStyle = (dp->selection.startDocOffset == dp->selection.endDocOffset);
  2221.  
  2222.     SetSelection(dp, docOffset, docOffset, setEmptyStyle, false, true);
  2223.     
  2224. }
  2225.  
  2226. static void Clear(DocPtr dp)
  2227. {
  2228.     ParaPtr            pp;
  2229.     long            start;
  2230.     long            end;
  2231.     short            paragraphIndex;
  2232.     short            paragraphOffset;
  2233.     short            numText;
  2234.     long            size;
  2235.     Boolean            needToJoin;
  2236.     short            paraText;
  2237.     short            index;
  2238.     short            startIndex;
  2239.     
  2240.     if(dp->selection.startDocOffset == dp->selection.endDocOffset)
  2241.         return;        /* nothing to clear */
  2242.         
  2243.     /* make sure we don't clear the entire docuemnt -- leave at least one empty paragraph */
  2244.     
  2245.     if(dp->selection.startDocOffset == 0 && dp->selection.endDocOffset == dp->numText)
  2246.         dp->selection.endDocOffset--;
  2247.         
  2248.     start = dp->selection.startDocOffset;
  2249.     end = dp->selection.endDocOffset;
  2250.             
  2251.     numText = end - start;
  2252.         
  2253.     /* find out where to start */
  2254.     
  2255.     HLock((Handle) dp->paragraphs);
  2256.     
  2257.     GetParagraphIndexAndOffset(dp, start, ¶graphIndex, ¶graphOffset, false);
  2258.     
  2259.     startIndex = index = paragraphIndex;
  2260.     
  2261.     needToJoin = false;
  2262.     
  2263.     if(paragraphOffset != 0) {
  2264.     
  2265.         pp = *dp->paragraphs + index;
  2266.         
  2267.         paraText = pp->numText - paragraphOffset;
  2268.         
  2269.         if(numText < paraText)
  2270.             paraText = numText;
  2271.         else {
  2272.             paraText--;        /* don't delete '\r' */
  2273.             needToJoin = true;
  2274.         }
  2275.                     
  2276.         ParagraphClear(dp, pp, paragraphOffset, paraText);
  2277.         
  2278.         numText -= paraText;
  2279.         
  2280.         if(needToJoin)
  2281.             numText--;        /* the '\r' will be removed when the paragraphs are joined */
  2282.                 
  2283.         index++;
  2284.         
  2285.     }
  2286.     
  2287.     while(numText) {
  2288.     
  2289.         pp = *dp->paragraphs + index;
  2290.         
  2291.         if(numText >= pp->numText) {
  2292.         
  2293.             numText -= pp->numText;
  2294.             
  2295.             gxEditDisposeParagraph(dp, pp);
  2296.             
  2297.             dp->numParagraphs--;
  2298.             
  2299.             size = (dp->numParagraphs - index) * sizeof(ParaRec);
  2300.             BlockMove((Ptr) (pp+1), (Ptr) pp, size);
  2301.             
  2302.             HUnlock((Handle) dp->paragraphs);
  2303.             
  2304.             size = dp->numParagraphs * sizeof(ParaRec);
  2305.             SetHandleSize((Handle) dp->paragraphs, size);
  2306.             
  2307.             HLock((Handle) dp->paragraphs);
  2308.             
  2309.         } else {
  2310.         
  2311.             ParagraphClear(dp, pp, 0, numText);
  2312.             
  2313.             numText = 0;
  2314.             
  2315.             
  2316.         
  2317.         }
  2318.         
  2319.     }
  2320.     
  2321.     if(needToJoin && index != dp->numParagraphs) {
  2322.     
  2323.         pp = *dp->paragraphs + index;
  2324.         
  2325.         JoinParagraphs(dp, pp-1, pp);
  2326.         
  2327.         dp->numParagraphs--;
  2328.         
  2329.         size = (dp->numParagraphs - index) * sizeof(ParaRec);
  2330.         BlockMove((Ptr) (pp+1), (Ptr) pp, size);
  2331.         
  2332.         HUnlock((Handle) dp->paragraphs);
  2333.         
  2334.         size = dp->numParagraphs * sizeof(ParaRec);
  2335.         SetHandleSize((Handle) dp->paragraphs, size);
  2336.         
  2337.         HLock((Handle) dp->paragraphs);
  2338.     
  2339.     }
  2340.     
  2341.     HUnlock((Handle) dp->paragraphs);
  2342.     
  2343.     CalcOffsets(dp, paragraphIndex);
  2344.     
  2345.     dp->dirty = true;                    /* CalcStarts(dp, paragraphIndex); */
  2346.     
  2347.     SetSelection(dp, dp->selection.startDocOffset, dp->selection.startDocOffset, false, false, true);
  2348.     
  2349. }
  2350.  
  2351. static void CheckCaretVisibility(DocPtr dp)
  2352. {
  2353.     long                start, end;
  2354.     short            dv;
  2355.     
  2356.     /* scroll the screen if the caret is not in the visible area */
  2357.     
  2358.     Position(dp, dp->selection.startDocOffset, &start, &end);
  2359.     
  2360.     if(end > dp->top + dp->viewHeight) {
  2361.     
  2362.         dv = dp->top - (end - dp->viewHeight);
  2363.     
  2364.         DocScroll(dp, dv);
  2365.         
  2366.     }
  2367.     
  2368. }
  2369.  
  2370. static void Paste(DocPtr dp)
  2371. {
  2372.     NewRunPtr        rp;
  2373.     short            runIndex;
  2374.     
  2375.     if(dp->scrap.numRuns == 0)
  2376.         return;        /* no scrap text to paste */
  2377.         
  2378.     HLock((Handle) dp->scrap.runs);
  2379.     
  2380.     rp = *(dp->scrap.runs);
  2381.     
  2382.     for(runIndex=0; runIndex < dp->scrap.numRuns; runIndex++, rp++) {
  2383.     
  2384.         HLock((Handle) rp->text);
  2385.         
  2386.         Insert(dp, *rp->text, rp->numText, rp->styleIndex);
  2387.  
  2388.         HUnlock((Handle) rp->text);
  2389.     }
  2390.     
  2391.     HUnlock((Handle) dp->scrap.runs);
  2392. }
  2393.  
  2394. static void Copy(DocPtr dp)
  2395. {
  2396.     ParaPtr                pp;
  2397.     NewRunPtr            rp;
  2398.     short                paragraphIndex;
  2399.     short                runIndex;
  2400.     long                start;
  2401.     long                numText;
  2402.     NewRunRec            run;
  2403.     long                size;
  2404.     ScrapPtr            scrap;
  2405.     short                numAppendText;
  2406.     
  2407.     start = dp->selection.startDocOffset;
  2408.     numText = dp->selection.endDocOffset - start;
  2409.  
  2410.     if(!numText)
  2411.         return;            /* nothing to copy */
  2412.         
  2413.     scrap = &dp->scrap;
  2414.     
  2415.     /* clear out the current scrap */
  2416.     
  2417.     gxEditEmptyScrap(dp);
  2418.     
  2419.     /* set scrap length while we have the correct text count available */
  2420.     
  2421.     scrap->numText = numText;
  2422.         
  2423.     /* get to the start of the selection and make a copy of the first partial run,
  2424.        all intermediate runs and the partial last run */
  2425.        
  2426.     HLock((Handle) dp->paragraphs);
  2427.     
  2428.     pp = *dp->paragraphs;
  2429.     
  2430.     for(paragraphIndex=0; paragraphIndex < dp->numParagraphs; paragraphIndex++, pp++)
  2431.         if(start < (pp->docOffset + pp->numText))
  2432.             break;
  2433.             
  2434.     if(paragraphIndex == dp->numParagraphs)
  2435.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  2436.         
  2437.     start -= pp->docOffset;
  2438.         
  2439.     HLock((Handle) pp->runs);
  2440.     
  2441.     rp = *pp->runs;
  2442.     
  2443.     for(runIndex = 0; runIndex < pp->numRuns; runIndex++, rp++)
  2444.         if(start < (rp->paraOffset + rp->numText))
  2445.             break;
  2446.             
  2447.     if(runIndex == pp->numRuns)
  2448.         gxEditPostError(dp, gx_edit_internal_fatal_error);
  2449.         
  2450.     start -= rp->paraOffset;
  2451.         
  2452.     /* grab the text */
  2453.         
  2454.     run.styleIndex = rp->styleIndex;
  2455.     
  2456.     IncrementDocStyleRefCount(dp, run.styleIndex);
  2457.     
  2458.     run.numText = rp->numText - start;
  2459.     
  2460.     if(run.numText > numText)
  2461.         run.numText = numText;
  2462.     
  2463.     size = run.numText;
  2464.     run.text = (void **) NewHandle(size);
  2465.     
  2466.     BlockMove((Ptr) ((long) *rp->text + (start)), (Ptr) *run.text, size);
  2467.     
  2468.     PtrAndHand((Ptr) &run, (Handle) scrap->runs, sizeof(NewRunRec));
  2469.     scrap->numRuns++;
  2470.     
  2471.     numText -= run.numText;
  2472.     
  2473.     runIndex++;
  2474.     rp++;
  2475.         
  2476.     while(numText) {
  2477.     
  2478.         if(runIndex == pp->numRuns) {
  2479.         
  2480.             HUnlock((Handle) pp->runs);
  2481.             
  2482.             paragraphIndex++;
  2483.             pp++;
  2484.                 
  2485.             if(paragraphIndex == dp->numParagraphs)
  2486.                 gxEditPostError(dp, gx_edit_internal_fatal_error);
  2487.                     
  2488.             HLock((Handle) pp->runs);
  2489.                 
  2490.             rp = *pp->runs;
  2491.             runIndex = 0;
  2492.                     
  2493.         }
  2494.         
  2495.         if(rp->styleIndex == run.styleIndex) {
  2496.         
  2497.             /* just add the text to the last scrap run */
  2498.  
  2499.             numAppendText = rp->numText;
  2500.                         
  2501.             if(numAppendText > numText)
  2502.                 numAppendText = numText;
  2503.             
  2504.             size = (run.numText + numAppendText);
  2505.             SetHandleSize((Handle) run.text, size);
  2506.             
  2507.             size = numAppendText;
  2508.             BlockMove((Ptr) *rp->text, (Ptr) ((long) *run.text + (run.numText)), size);
  2509.             
  2510.             run.numText += numAppendText;
  2511.  
  2512.             BlockMove((Ptr) &run, (Ptr) (*scrap->runs + scrap->numRuns - 1), sizeof(NewRunRec));
  2513.             
  2514.             numText -= numAppendText;
  2515.             
  2516.         } else {
  2517.         
  2518.             /* add a new run to the scrap */
  2519.  
  2520.             run.styleIndex = rp->styleIndex;
  2521.  
  2522.             IncrementDocStyleRefCount(dp, run.styleIndex);
  2523.     
  2524.             run.numText = rp->numText;
  2525.             
  2526.             if(run.numText > numText)
  2527.                 run.numText = numText;
  2528.             
  2529.             size = run.numText;
  2530.             run.text = (void **) NewHandle(size);
  2531.             
  2532.             BlockMove((Ptr) *rp->text, (Ptr) *run.text, size);
  2533.             
  2534.             PtrAndHand((Ptr) &run, (Handle) scrap->runs, sizeof(NewRunRec));
  2535.             scrap->numRuns++;
  2536.             
  2537.             numText -= run.numText;
  2538.             
  2539.         }
  2540.         
  2541.         if(numText == 0)
  2542.             break;
  2543.             
  2544.         runIndex++;
  2545.         rp++;
  2546.         
  2547.     }
  2548.     
  2549.     HUnlock((Handle) pp->runs);
  2550.     HUnlock((Handle) dp->paragraphs);
  2551.     
  2552. }
  2553.  
  2554. static void DoEraseToEndOfView(DocPtr dp)
  2555. {
  2556.     Rect                rect;
  2557.     gxRectangle        aRect;
  2558.     gxShape            eraser;
  2559.     ParaPtr            pp;
  2560.     
  2561.     pp = *dp->paragraphs + dp->numParagraphs - 1;
  2562.     
  2563.     if(dp->verticalText) {
  2564.     
  2565.         rect.top = dp->viewRect.top;
  2566.         rect.bottom = dp->viewRect.bottom;
  2567.         rect.right = dp->viewRect.right  - (pp->start + GetParagraphHeight(dp, pp) - dp->top);
  2568.         rect.left = dp->bottomClear;
  2569.  
  2570.         if(rect.right > rect.left) {
  2571.         
  2572.             aRect.top = ff(rect.top);
  2573.             aRect.left = ff(rect.left);
  2574.             aRect.bottom = ff(rect.bottom);
  2575.             aRect.right = ff(rect.right);
  2576.             
  2577.             eraser = GXNewRectangle(&aRect);
  2578.             
  2579.             /* This ignores is needed because we do not keep track of the current
  2580.                   clip of the view port.  Thus, we will often set the clip to the same rect
  2581.                   which generates a notice*/
  2582.  
  2583. #ifdef debugging
  2584.             GXIgnoreGraphicsNotice(clip_already_set);
  2585. #endif
  2586.  
  2587.             GXSetViewPortClip(dp->docViewPort, eraser);
  2588.             
  2589. #ifdef debugging
  2590.             GXPopGraphicsNotice();
  2591. #endif
  2592.     
  2593.             SetShapeCommonColor(eraser, gxWhite);
  2594.             GXSetShapeViewPorts(eraser, 1, &dp->docViewPort);
  2595.             GXDrawShape(eraser);
  2596.             
  2597.             GXDisposeShape(eraser);
  2598.             
  2599.             dp->bottomClear = rect.right;
  2600.         }
  2601.     } else {
  2602.     
  2603.         rect.top = pp->start + GetParagraphHeight(dp, pp) + dp->viewRect.top - dp->top;
  2604.         rect.bottom = dp->bottomClear;
  2605.         rect.left = dp->viewRect.left;
  2606.         rect.right = dp->viewRect.right;
  2607.         
  2608.         if(rect.top < rect.bottom) {
  2609.         
  2610.             aRect.top = ff(rect.top);
  2611.             aRect.left = ff(rect.left);
  2612.             aRect.bottom = ff(rect.bottom);
  2613.             aRect.right = ff(rect.right);
  2614.             
  2615.             eraser = GXNewRectangle(&aRect);
  2616.             
  2617.             /* This ignores is needed because we do not keep track of the current
  2618.                   clip of the view port.  Thus, we will often set the clip to the same rect
  2619.                   which generates a notice*/
  2620.  
  2621. #ifdef debugging
  2622.             GXIgnoreGraphicsNotice(clip_already_set);
  2623. #endif
  2624.  
  2625.             GXSetViewPortClip(dp->docViewPort, eraser);
  2626.             
  2627. #ifdef debugging
  2628.             GXPopGraphicsNotice();
  2629. #endif
  2630.     
  2631.             SetShapeCommonColor(eraser, gxWhite);
  2632.             GXSetShapeViewPorts(eraser, 1, &dp->docViewPort);
  2633.             GXDrawShape(eraser);
  2634.             
  2635.             GXDisposeShape(eraser);
  2636.             
  2637.             dp->bottomClear = rect.top;
  2638.         }
  2639.     }
  2640.                 
  2641. }
  2642.  
  2643. static void GetOffset(DocPtr dp, short offsetType, long * newOffset, Boolean * endOfLine)
  2644. {
  2645.     long            docOffset;
  2646.     short        paraIndex, paraOffset;
  2647.     short        lineIndex, lineOffset;
  2648.     ParaPtr        pp;
  2649.     LinePtr        lp;
  2650.     
  2651.     docOffset = *newOffset;
  2652.     
  2653.     GetParagraphIndexAndOffset(dp, docOffset, ¶Index, ¶Offset, *endOfLine);
  2654.     
  2655.      pp = *dp->paragraphs + paraIndex;
  2656.      docOffset = pp->docOffset;
  2657.      
  2658.      switch(offsetType) {
  2659.      
  2660.      case kUpOffset:
  2661.      
  2662.          *endOfLine = (dp->maxLineOffset != 0);
  2663.          
  2664.          GetLineIndexAndOffset(dp, pp, paraOffset, &lineIndex, &lineOffset, *endOfLine);
  2665.          
  2666.          if(paraIndex == 0&& lineIndex == 0) 
  2667.              return;
  2668.          
  2669.          if(lineIndex == 0) {
  2670.              pp--;
  2671.              lineIndex = pp->numLines - 1;
  2672.          } else
  2673.              lineIndex--;
  2674.              
  2675.          goto skip;
  2676.               
  2677.      case kDownOffset:
  2678.      
  2679.          *endOfLine = (dp->maxLineOffset != 0);
  2680.          
  2681.          GetLineIndexAndOffset(dp, pp, paraOffset, &lineIndex, &lineOffset, *endOfLine);
  2682.          
  2683.          if(paraIndex == (dp->numParagraphs - 1) && lineIndex == (pp->numLines - 1))
  2684.              return;
  2685.          
  2686.          if(lineIndex == (pp->numLines - 1)) {
  2687.              pp++;
  2688.              lineIndex = 0;
  2689.          } else
  2690.              lineIndex++;
  2691.              
  2692. skip:
  2693.          
  2694.          lp = *pp->lines + lineIndex;
  2695.          lineOffset = dp->maxLineOffset;
  2696.          
  2697.          if(lineOffset > lp->numText) {
  2698.          
  2699.              lineOffset = lp->numText;
  2700.              
  2701.              if(lineIndex == (pp->numLines - 1))
  2702.                  lineOffset--;        /* end of paragraph is allways a single byte '\n' */
  2703.                  
  2704.          }
  2705.          
  2706.          *newOffset = pp->docOffset + lp->paraOffset + lineOffset;
  2707.          
  2708.          return;
  2709.          
  2710.      case kVisualRightOffset:
  2711.      
  2712.          if(paraOffset != pp->numText - 1)
  2713.              break;
  2714.          
  2715.          if(paraIndex < (dp->numParagraphs - 1))
  2716.              docOffset++;        /* end of paragraph is allways a single byte '\n' */
  2717.          
  2718.          *newOffset = docOffset + paraOffset;
  2719.          *endOfLine = false;
  2720.          return;
  2721.      
  2722.      case kPreviousOffset:
  2723.      case kVisualLeftOffset:
  2724.      
  2725.          if(paraOffset > 0)
  2726.              break;
  2727.          
  2728.          if(paraIndex > 0)
  2729.              docOffset--;        /* end of paragraph is allways a single byte '\n' */
  2730.          
  2731.          *newOffset = docOffset;
  2732.          *endOfLine = false;
  2733.          return;
  2734.          
  2735.     }
  2736.     
  2737.     *newOffset = docOffset + GetParagraphOffset(dp, pp, offsetType, paraOffset);
  2738.     *endOfLine = false;
  2739. }
  2740.  
  2741.